import java.util.*;
import java.io.*;
import antlr.CommonAST;
import antlr.collections.AST;
import antlr.RecognitionException;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.debug.misc.ASTFrame;
class Sim2dInterpreter {
	sim2dWalker walker;
   private static Sim2dInterpreter ref;
	private boolean object_definition_mode;
	public Sim2dSymbolTable sym;
   private Sim2dInterpreter() {
      sym = new Sim2dSymbolTable( null );
		object_definition_mode = false;
      put(new Sim2ddistance_to("distance_to"));
      put(new Sim2dbearing_to("bearing_to"));
      put(new Sim2darccos("arccos"));
   }
   public static Sim2dInterpreter getInstance()
   {
     if (ref == null)
         ref = new Sim2dInterpreter();
     return ref;
   }
	public void setWalker(sim2dWalker inwalker) {
		walker = inwalker;
	}
   public boolean put(Sim2dDataType data) {
		return sym.put(data);
	}
   public boolean put_into_obj(Sim2dDataType lvalue, Sim2dDataType rvalue) {
		if (lvalue.name == null) {
			throw new Sim2dException("Invalid lvalue");
		}
		Sim2dDataType symbol = sym.getLast();
      log.out("put_into_obj:  " + symbol.name);
		if (!(symbol instanceof Sim2dObject)) {
			throw new Sim2dException(" trying to put data into object, but last symbol in symbol table is not a Sim2dObject");
		}
		Sim2dDataType newsymbol = rvalue.copy();
		newsymbol.setName(lvalue.getName());
		Sim2dObject objsymbol = (Sim2dObject)symbol;
		objsymbol.put(newsymbol);
		return true;
	}

   public boolean assign(Sim2dDataType lvalue, Sim2dDataType rvalue) {
		if (lvalue.name == null) {
			throw new Sim2dException("Invalid lvalue");
		}
		lvalue.assign(rvalue);

		return true;
	}

   public Sim2dDataType[] convertExprList( Vector v ) {
       Sim2dDataType[] x = new Sim2dDataType[v.size()];
       for ( int i=0; i<x.length; i++ )
           x[i] = (Sim2dDataType) v.elementAt( i );
       return x;
   }


	public void objectPostProcessing () {
		Sim2dDataType symbol = sym.getLast();
      log.out("objectPostProcessing:  " + symbol.name);
		if (!(symbol instanceof Sim2dObject)) {
			throw new Sim2dException(" trying to put data into object, but last symbol in symbol table is not a Sim2dObject");
		}
		Sim2dObject objsymbol = (Sim2dObject)symbol;
		objsymbol.putInternalFields();
	}
	public Sim2dDataType getSymbol(String name) {
		Sim2dDataType symbol = sym.get(name);
		if (getObjectDefinitionMode()) {
			if (symbol == null) {
 				return new Sim2dDataType(name);
			} else {
				throw new Sim2dException("Multiple symbols named " + name);
			}
		} else {
			if (symbol == null) {
				throw new Sim2dException("Unknown symbol " + name);
			} else {
			}
		}
		return symbol;
	}
	public boolean getObjectDefinitionMode() {
		return object_definition_mode;
	}
	public void setObjectDefinitionMode(boolean mode) {
		object_definition_mode = mode;
	}
	public Sim2dDataType getNumber(String a) {
		try {
		   return new Sim2dInt(Integer.parseInt(a));
		} catch (NumberFormatException e) {
		}
		try {
		   return new Sim2dFloat(Float.parseFloat(a));
		} catch (NumberFormatException e) {
			throw new Sim2dException("invalid number");
		}
	}
	public void enterScope() {
		Sim2dSymbolTable newsym;
		newsym = new Sim2dSymbolTable( sym );
		sym = newsym;
	}
	public void leaveScope() {
		sym = sym.parent;
		// The symbol table for the scope we are leaving
		// will be destroyed by the garbage collector
	}
	public boolean runRule(Sim2dObject obj)
     throws antlr.RecognitionException	{
		boolean rule_found = false;
		for (Sim2dDataType symbol : sym) {
			if (symbol.getName().equals(obj.getName()) 
					&& symbol instanceof Sim2dRule ) {
				Sim2dRule rule = (Sim2dRule)symbol;
				// create a new symobl table for the scope of the rule
				// and put the objects symbols into it
				enterScope();
				for (Sim2dDataType field : obj.fields.values()) {
					sym.put(field);
				}
				walker.expr(rule.getBody());
				leaveScope();
				rule_found = true;
			}
		}
		return rule_found;

	}

}


